package v1

import (
	"cn.bupt.byy/monitor/config"
	"cn.bupt.byy/monitor/service"
	"cn.bupt.byy/monitor/service/impl"
	"context"
	"github.com/gin-gonic/gin"
	v1 "k8s.io/api/core/v1"
	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"log"
	"net/http"
	"strings"
	"sync"
)

type RunningNodesReq []string

var (
	operaSvc service.OperationService
	moSvc    service.MonitorService
	_        []string // 每个nodeName 最后一位 例如: k8s-node-8 => v=8
	mu       sync.Mutex
)

func init() {
	operaSvc = new(impl.OperationServiceImpl)
	moSvc = new(impl.MonitorServiceImpl)
}

// CreateApp
// @Summary 在任意节点上创建任务
// @Description
// @Produce  json
// @Success 200 {object} models.Byy "ok"
// @Router /operation [get]
func CreateApp(c *gin.Context) {
	operaSvc.Create(c)

	updateRunningNodesByRunningPods(c)

	c.JSON(http.StatusOK, moSvc.ListAll(c))
}

// DeleteApp
// @Summary 删除任务
// @Description
// @Produce  json
// @Success 200 {object} models.Byy "ok"
// @Router /operation [delete]
func DeleteApp(c *gin.Context) {
	operaSvc.Delete(c)
	c.JSON(http.StatusOK, moSvc.ListAll(c))
}

// CreateAppOnAssignmentNode
// @Summary 在指定节点上创建任务
// @Description 输入参数["1","2"] 将在 k8s-node-1 和 k8s-node-2 上启动任务
// @Accept json
// @Produce  json
// @Param data body []string true "节点列表"
// @Success 200 {object} models.Byy "ok"
// @Failure 400 {object} interface{} "序列化问题"
// @Router /operation [post]
func CreateAppOnAssignmentNode(c *gin.Context) {
	req := validRNS(c)

	operaSvc.CreateIn(c, req)

	updateRunningNodesByRunningPods(c)

	c.JSON(http.StatusOK, moSvc.ListAll(c))
}

// PutAppOnAssignmentNode
// @Summary 迁移已有任务至指定节点
// @Description 输入参数["1","2"] 将在 k8s-node-1 和 k8s-node-2 上启动任务
// @Accept json
// @Produce  json
// @Param data body []string true "节点列表"
// @Success 200 {object} models.Byy "ok"
// @Failure 400 {object} interface{} "序列化问题"
// @Router /operation [put]
func PutAppOnAssignmentNode(c *gin.Context) {
	req := validRNS(c)

	operaSvc.Delete(c)
	operaSvc.CreateIn(c, req)

	updateRunningNodesByRunningPods(c)

	c.JSON(http.StatusOK, moSvc.ListAll(c))
}

func updateRunningNodesByRunningPods(c context.Context) {
	w, err := coreV1.Pods(namespace).Watch(c, metaV1.ListOptions{})
	if err != nil {
		panic(err)
	}
	var res []string
	for event := range w.ResultChan() {
		p, ok := event.Object.(*v1.Pod)
		if !ok {
			log.Fatal("unexpected type")
		}
		if p.ObjectMeta.DeletionTimestamp == nil && p.Spec.NodeName != "" {
			sl := strings.Split(p.Spec.NodeName, "-")
			res = append(res, sl[len(sl)-1])
		}
		if int32(len(res)) == *config.ByyDeploy.Spec.Replicas {
			break
		}
	}
	mu.Lock()
	defer mu.Unlock()
	_ = res
}

func validRNS(c *gin.Context) (req RunningNodesReq) {
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
	}

	if int32(len(req)) < *config.ByyDeploy.Spec.Replicas {
		c.JSON(http.StatusBadRequest, "可分配节点数小于需要运行节点数")
	}
	return
}
